package com.example.demo.service;

import com.example.demo.dao.JobDao;
import com.example.demo.job.SpringBeanJob;
import com.example.demo.model.Job;
import com.example.demo.util.Res;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Method;
import java.util.List;

/**
 * @Description 描述
 * @Date 2021-01-13 5:02 下午
 * @Author wuyanshen
 */
@Service
public class JobServiceImpl implements JobService{

    private static final String JOB_DATA_KEY = "JOB_DATA_KEY";

    @Autowired
    private Scheduler scheduler;
    @Autowired
    private JobDao jobDao;
    @Autowired
    private ApplicationContext applicationContext;


    @Override
    public List<Job> all() {
        return jobDao.all();
    }

    @Transactional
    @Override
    public void saveJob(Job job)  {

        String name = job.getJobName();
        JobKey jobKey = JobKey.jobKey(name);

        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCron())
                // 以当前时间为触发频率立刻触发一次执行
                // 然后按照Cron频率依次执行
                //.withMisfireHandlingInstructionFireAndProceed()
                // 不触发立即执行, 等待下次Cron触发频率到达时刻开始按照Cron频率依次执行
                .withMisfireHandlingInstructionDoNothing();
                // 以错过的第一个频率时间立刻开始执行
                // 重做错过的所有频率周期后
                // 当下一次触发频率发生时间大于当前时间后，再按照正常的Cron频率依次执行
                //.withMisfireHandlingInstructionIgnoreMisfires();
        // 构建job信息
        JobDetail jobDetail = JobBuilder
                .newJob(SpringBeanJob.class)
                .storeDurably()
                .withIdentity(job.getJobName())
                .withDescription(job.getDescription())
                .build();
        jobDetail.getJobDataMap().put(JOB_DATA_KEY, job);
        // 触发时间
        CronTrigger trigger = TriggerBuilder
                .newTrigger()
                .withIdentity(job.getJobName())
                .withSchedule(cronScheduleBuilder)
                .build();

        try {
            boolean exists = scheduler.checkExists(jobKey);
            if (exists) {
                scheduler.rescheduleJob(new TriggerKey(name), trigger);
                scheduler.addJob(jobDetail, true);
            } else {
                //交由Scheduler安排触发
                scheduler.scheduleJob(jobDetail, trigger);
            }
            Job model = jobDao.getByName(name);
            if (model == null) {
                jobDao.add(job);
            } else {
                jobDao.update(job);
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }

    }

    @Transactional
    @Override
    public void delete(Job job) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName());
            // 停止触发器
            scheduler.pauseTrigger(triggerKey);
            // 移除触发器
            scheduler.unscheduleJob(triggerKey);
            // 删除任务
            scheduler.deleteJob(JobKey.jobKey(job.getJobName()));

            jobDao.delete(job.getId());

        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void doJob(JobDataMap jobDataMap) {
        Job jobModel = (Job) jobDataMap.get(JOB_DATA_KEY);

        String beanName = jobModel.getBeanClass();
        String methodName = jobModel.getMethodName();
        Object object = applicationContext.getBean(beanName);

        try {
            Method method = object.getClass().getDeclaredMethod(methodName);
            method.invoke(object);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void update(Job job) {
        jobDao.update(job);
    }
}
